package com.example.demo.test;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author: ak
 * @date: 2020/7/12 18:20
 * @description:
 */
public class ProtectivePause {
    public static void main(String[] args) throws InterruptedException {
        int threadNums = 3;
        for (int i = 0; i < threadNums; i++) {
            new Person("居民" + (i + 1)).start();
        }
        TimeUnit.SECONDS.sleep(1);
        Set<Integer> ids = MailBox.getIds();
        for (Integer id : ids) {
            new PostMan(id, "信封内容" + id, "邮递员" + id).start();
        }
    }
}

@Slf4j
class Person extends Thread {
    public Person(String name) {
        super(name);
    }

    @SneakyThrows
    @Override
    public void run() {
        GuarderObject guarder = MailBox.createGuarder();
        log.info("居民开始收信去id为{}的信箱收信", guarder.id);
        Object o = guarder.get(2000);
        if (o == null) {
            log.info("居民还没收到信，邮递员巨NMD慢");
            return;
        }
        log.info("居民收到了信{}", o);

    }
}

@Slf4j
class PostMan extends Thread {
    int guarderId;

    String content;

    public PostMan(int guarderId, String content, String name) {
        super(name);
        this.guarderId = guarderId;
        this.content = content;
    }

    @SneakyThrows
    @Override
    public void run() {
        log.info("邮递员开始送信id为{}的信箱,内容为{}", guarderId, content);
        GuarderObject guarder = MailBox.getGuarder(guarderId);
        guarder.sentMail(content, 4);
        log.info("邮递员送信完成");
    }
}

class MailBox {
    private static final Map<Integer, GuarderObject> BOX = new Hashtable<>();
    private static int id = 1;

    private static synchronized int getId() {
        return id++;
    }

    public static GuarderObject createGuarder() {
        GuarderObject object = new GuarderObject(getId());
        BOX.put(object.id, object);
        return object;
    }

    public static GuarderObject getGuarder(int id) {
        return BOX.remove(id);
    }

    public static Set<Integer> getIds() {
        return BOX.keySet();
    }

}

@Slf4j
class GuarderObject {
    int id;

    public GuarderObject(int id) {
        this.id = id;
    }

    public Object response = null;

    public synchronized Object get(long timeOut) throws InterruptedException {
        long begin = System.currentTimeMillis();
        long passTime = 0;
        while (response == null) {
            long waitTime = timeOut - passTime;
            if (waitTime <= 0) {
                break;
            }
            log.info("waitTime : {}", waitTime);
            this.wait(waitTime);
            passTime = System.currentTimeMillis() - begin;
            log.info(String.valueOf(passTime));
        }
        return response;
    }

    public void sentMail(Object o, long neededTime) throws InterruptedException {
        Thread.sleep(neededTime * 1000);
        synchronized (this) {
            response = o;
            this.notifyAll();
        }
    }

}
